﻿using FakeXiecheng.API.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using FakeXiecheng.API.Dtos;
using AutoMapper;
using FakeXiecheng.API.ResourceParameters;
using FakeXiecheng.API.Moldes;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using FakeXiecheng.API.Helper;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Formatters;
using System.Dynamic;
using Microsoft.Net.Http.Headers;

namespace FakeXiecheng.API.Controllers
{
    /// <summary>
    /// 旅游路线
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class TouristRoutesController : ControllerBase
    {
        //System.Linq.Dynamic.Core 字符串排序插件
        private ITouristRouteRepository _touristRouteRepository;
        private readonly IMapper _mapper;
        private readonly IUrlHelper _urlHelper;
        private readonly IPropertyMappingService _propertyMappingService;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ouristRouteRepository"></param>
        public TouristRoutesController(
            ITouristRouteRepository ouristRouteRepository, 
            IMapper mapper,IUrlHelperFactory urlHelperFactory,
            IActionContextAccessor actionContextAccessor,
            IPropertyMappingService propertyMappingService
            )
        {
            _touristRouteRepository = ouristRouteRepository;
            _mapper = mapper;
            _urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
            _propertyMappingService = propertyMappingService;
        }
        //高端分页URL函数
        //1.TouristRouteResourceParamaters旅游路线参数
        //2.PaginationResourceParamaters 分页参数
        //3.ResourceUriType url类型 枚举文件
        //_urlHelper 服务分三个步骤  1.打开Startup 2.打开TouristRoutesController 添加私有成员变量 IUrlHelper 3.构造函数中注入服务
        private string GenerateTouristRouteResourceURL(
            TouristRouteResourceParamaters paramaters,
            PaginationResourceParamaters paramaters1,
            ResourceUriType type
        )
        {
            return type switch
            {
                ResourceUriType.PreviousPage => _urlHelper.Link("GerTouristRoutes",
                    new
                    {
                        fileds=paramaters.Fields,//上一页
                        orderBy=paramaters.OrderBy,
                        keyword = paramaters.Keyword,
                        rating = paramaters.Rating,
                        pageNumber = paramaters1.PageNumber - 1,
                        pageSize = paramaters1.PageSize
                    }),
                ResourceUriType.NextPage => _urlHelper.Link("GerTouristRoutes",
                    new
                    {
                        fileds = paramaters.Fields,//下一页
                        orderBy = paramaters.OrderBy,
                        keyword = paramaters.Keyword,
                        rating = paramaters.Rating,
                        pageNumber = paramaters1.PageNumber + 1,
                        pageSize = paramaters1.PageSize
                    }),
                _ => _urlHelper.Link("GerTouristRoutes",
                    new
                    {
                        fileds = paramaters.Fields,//默认页
                        orderBy = paramaters.OrderBy,
                        keyword = paramaters.Keyword,
                        rating = paramaters.Rating,
                        pageNumber = paramaters1.PageNumber,
                        pageSize = paramaters1.PageSize
                    })
            };
        }
        // api/touristRoutes?keyword=传入的参数
        // 1. application/json -> 旅游路线资源
        // 2. application/vnd.aleks.hateoas+json
        // 3. application/vnd.aleks.touristRoute.simplify+json -> 输出简化版资源数据
        // 4. application/vnd.aleks.touristRoute.simplify.hateoas+json -> 输出简化版hateoas超媒体资源数据
        [Produces(
            "application/json",
            "application/vnd.aleks.hateoas+json",
            "application/vnd.aleks.touristRoute.simplify+json",
            "application/vnd.aleks.touristRoute.simplify.hateoas+json"
            )]
        //高端分页改造第二部分
        //api/touristRoutes?keyword=传入的参数
        [HttpGet(Name = "GerTouristRoutes")]
        [HttpHead]
        public async Task<IActionResult> GerTouristRoutes(
            [FromQuery] TouristRouteResourceParamaters paramaters,
            [FromQuery] PaginationResourceParamaters paramaters1,
            [FromHeader(Name = "Accept")] string mediaType
        //[FromQuery] string keyword,
        //string rating // 小于lessThan, 大于largerThan, 等于equalTo lessThan3, largerThan2, equalTo5 
        )// FromQuery vs FromBody
        {
            if (!MediaTypeHeaderValue
              .TryParse(mediaType, out MediaTypeHeaderValue parsedMediatype))
            {
                return BadRequest();
            }

            if (!_propertyMappingService
                .IsMappingExists<TouristRouteDto, TouristRoute>(
                paramaters.OrderBy))
            {
                return BadRequest("请输入正确的排序参数");
            }

            if (!_propertyMappingService
                .IsPropertiesExists<TouristRouteDto>(paramaters.Fields))
            {
                return BadRequest("请输入正确的塑性参数");
            }

            var touristRoutesFromRepo = await _touristRouteRepository
                .GetTouristRoutesAsync(
                    paramaters.Keyword,
                    paramaters.RatingOperator,
                    paramaters.RatingValue,
                    paramaters1.PageSize,
                    paramaters1.PageNumber,
                    paramaters.OrderBy
                );
            if (touristRoutesFromRepo == null || touristRoutesFromRepo.Count() <= 0)
            {
                return NotFound("没有旅游路线");
            }

            var previousPageLink = touristRoutesFromRepo.HasPrevious
                ? GenerateTouristRouteResourceURL(
                    paramaters, paramaters1, ResourceUriType.PreviousPage)
                : null;

            var nextPageLink = touristRoutesFromRepo.HasNext
                ? GenerateTouristRouteResourceURL(
                    paramaters, paramaters1, ResourceUriType.NextPage)
                : null;

            // x-pagination
            var paginationMetadata = new
            {
                previousPageLink,
                nextPageLink,
                totalCount = touristRoutesFromRepo.TotalCount,
                pageSize = touristRoutesFromRepo.PageSize,
                currentPage = touristRoutesFromRepo.CurrentPage,
                totalPages = touristRoutesFromRepo.TotalPages
            };

            Response.Headers.Add("x-pagination",
                Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetadata));

            bool isHateoas = parsedMediatype.SubTypeWithoutSuffix
                .EndsWith("hateoas", StringComparison.InvariantCultureIgnoreCase);

            var primaryMediaType = isHateoas
                ? parsedMediatype.SubTypeWithoutSuffix
                    .Substring(0, parsedMediatype.SubTypeWithoutSuffix.Length - 8)
                : parsedMediatype.SubTypeWithoutSuffix;

            //var touristRoutesDto = _mapper.Map<IEnumerable<TouristRouteDto>>(touristRoutesFromRepo);
            //var shapedDtoList = touristRoutesDto.ShapeData(paramaters.Fields);
            IEnumerable<object> touristRoutesDto;
            IEnumerable<ExpandoObject> shapedDtoList;

            if (primaryMediaType == "vnd.aleks.touristRoute.simplify")
            {
                touristRoutesDto = _mapper
                    .Map<IEnumerable<TouristRouteSimplifyDto>>(touristRoutesFromRepo);

                shapedDtoList = ((IEnumerable<TouristRouteSimplifyDto>)touristRoutesDto)
                    .ShapeData(paramaters.Fields);
            }
            else
            {
                touristRoutesDto = _mapper
                    .Map<IEnumerable<TouristRouteDto>>(touristRoutesFromRepo);
                shapedDtoList =
                    ((IEnumerable<TouristRouteDto>)touristRoutesDto)
                    .ShapeData(paramaters.Fields);
            }

            if (isHateoas)
            {
                var linkDto = CreateLinksForTouristRouteList(paramaters, paramaters1);

                var shapedDtoWithLinklist = shapedDtoList.Select(t =>
                {
                    var touristRouteDictionary = t as IDictionary<string, object>;
                    var links = CreateLinkForTouristRoute(
                        (Guid)touristRouteDictionary["Id"], null);
                    touristRouteDictionary.Add("links", links);
                    return touristRouteDictionary;
                });

                var result = new
                {
                    value = shapedDtoWithLinklist,
                    links = linkDto
                };

                return Ok(result);
            }

            return Ok(shapedDtoList);
            //if (!_propertyMappingService
            //    .IsMappingExists<TouristRouteDto, TouristRoute>(
            //    paramaters.OrderBy))
            //    {
            //        return BadRequest("请输入正确的排序参数");
            //    }
            //if(!_propertyMappingService.IsPropertiesExists<TouristRouteDto>(paramaters.Fields))
            //{
            //    return BadRequest("请输入正确的塑性参数");
            //}
            //var touristRoutesFromRepo = await _touristRouteRepository.GetTouristRoutesAsync(
            //    paramaters.Keyword,
            //    paramaters.RatingOperator,
            //    paramaters.RatingValue,
            //    paramaters1.PageSize,
            //    paramaters1.PageNumber,
            //    paramaters.OrderBy//System.Linq.Dynamic.Core 
            //    );
            //if (touristRoutesFromRepo == null || touristRoutesFromRepo.Count() <= 0)
            //{
            //    return NotFound("没有旅游路线");
            //}
            //var touristRoutesDto = _mapper.Map<IEnumerable<TouristRouteDto>>(touristRoutesFromRepo);
            ////判断是否存在上一页 不存在则为null
            //var previousPageLink = touristRoutesFromRepo.HasPrevious
            //    ? GenerateTouristRouteResourceURL(
            //        paramaters, paramaters1, ResourceUriType.PreviousPage)
            //    : null;
            ////判断是否存在下一页 不存在则为null
            //var nextPageLink = touristRoutesFromRepo.HasNext
            //    ? GenerateTouristRouteResourceURL(
            //        paramaters, paramaters1, ResourceUriType.NextPage)
            //    : null;

            //// x-pagination 头部信息
            //var paginationMetadata = new
            //{
            //    previousPageLink,
            //    nextPageLink,
            //    totalCount = touristRoutesFromRepo.TotalCount,
            //    pageSize = touristRoutesFromRepo.PageSize,
            //    currentPage = touristRoutesFromRepo.CurrentPage,
            //    totalPages = touristRoutesFromRepo.TotalPages
            //};

            //Response.Headers.Add("x-pagination",
            //    Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetadata));
            ////links

            //return Ok(touristRoutesDto.ShapeData(paramaters.Fields));
        }
        /// <summary>
        /// linkdto
        /// </summary>
        /// <param name="paramaters"></param>
        /// <param name="paramaters2"></param>
        /// <returns></returns>
        private IEnumerable<LinkDto> CreateLinksForTouristRouteList(
            TouristRouteResourceParamaters paramaters,
            PaginationResourceParamaters paramaters2)
        {
            var links = new List<LinkDto>();
            // 添加self，自我链接
            links.Add(new LinkDto(
                    GenerateTouristRouteResourceURL(
                        paramaters, paramaters2, ResourceUriType.CurrnetPage),
                    "self",
                    "GET"
                ));

            // "api/touristRoutes"
            // 添加创建旅游路线
            links.Add(new LinkDto(
                    Url.Link("CreateTouristRoute", null),
                    "create_tourist_route",
                    "POST"
                ));

            return links;
        }
        //public async Task<IActionResult> GerTouristRoutesAsync(
        //    [FromQuery] TouristRouteResourceParamaters paramaters,
        //    [FromQuery] PaginationResourceParamaters paramaters1
        ////[FromQuery] string keyword,
        ////string rating // 小于lessThan, 大于largerThan, 等于equalTo lessThan3, largerThan2, equalTo5 
        //)// FromQuery vs FromBody
        //{
        //    var touristRoutesFromRepo = await _touristRouteRepository.GetTouristRoutesAsync(
        //        paramaters.Keyword, 
        //        paramaters.RatingOperator, 
        //        paramaters.RatingValue,
        //        paramaters1.PageSize,
        //        paramaters1.PageNumber
        //        );
        //    if (touristRoutesFromRepo == null || touristRoutesFromRepo.Count() <= 0)
        //    {
        //        return NotFound("没有旅游路线");
        //    }
        //    var touristRoutesDto = _mapper.Map<IEnumerable<TouristRouteDto>>(touristRoutesFromRepo);
        //    return Ok(touristRoutesDto);
        //}

        //api/touristroutes/{touristRouteId}
        [HttpGet("{touristRouteId}",Name= "GetTouristRouteById")]
        [HttpHead]
        public async Task<IActionResult> GetTouristRouteById(Guid touristRouteId, string fields) 
        {
            var touristRouteFromRepo =await _touristRouteRepository.GetToruistRouteAsync(touristRouteId);
            if(touristRouteFromRepo==null)
            {
                return NotFound($"旅游路线{touristRouteId}找不到");
            }
            //var touristRouteDto = new TouristRouteDto()
            //{
            //    Id = touristRouteFromRepo.id,
            //    Title = touristRouteFromRepo.Title,
            //    Description = touristRouteFromRepo.Description,
            //    Price = touristRouteFromRepo.OriginalPrice * (decimal)(touristRouteFromRepo.DiscountPresent ?? 1),
            //    CreateTime = touristRouteFromRepo.CreateTime,
            //    UpdateTime = touristRouteFromRepo.UpdateTime,
            //    Features = touristRouteFromRepo.Features,
            //    Fees = touristRouteFromRepo.Fees,
            //    Notes = touristRouteFromRepo.Notes,
            //    Rating = touristRouteFromRepo.Rating,
            //    TravelDays = touristRouteFromRepo.TravelDays.ToString(),
            //    TripType = touristRouteFromRepo.TripType.ToString(),
            //    DepartureCity = touristRouteFromRepo.DepartureCity.ToString()
            //};
            var touristRouteDto=_mapper.Map<TouristRouteDto>(touristRouteFromRepo);
            //return Ok(touristRouteDto);
            var linkDtos = CreateLinkForTouristRoute(touristRouteId, fields);

            var result = touristRouteDto.ShapeData(fields)
                as IDictionary<string, object>;
            result.Add("links", linkDtos);

            return Ok(result);
        }
        /// <summary>
        /// LinkDto
        /// </summary>
        /// <param name="touristRouteId"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        private IEnumerable<LinkDto> CreateLinkForTouristRoute(
        Guid touristRouteId,
        string fields)
        {
            var links = new List<LinkDto>();

            links.Add(
                new LinkDto(
                    Url.Link("GetTouristRouteById", new { touristRouteId, fields }),
                    "self",
                    "GET"
                    )
                );

            // 更新
            links.Add(
                new LinkDto(
                    Url.Link("UpdateTouristRoute", new { touristRouteId }),
                    "update",
                    "PUT"
                    )
                );

            // 局部更新 
            links.Add(
                new LinkDto(
                    Url.Link("PartiallyUpdateTouristRoute", new { touristRouteId }),
                    "partially_update",
                    "PATCH")
                );

            // 删除
            links.Add(
                new LinkDto(
                    Url.Link("DeleteTouristRoute", new { touristRouteId }),
                    "delete",
                    "DELETE")
                );

            // 获取路线图片
            links.Add(
                new LinkDto(
                    Url.Link("GetPictureListForTouristRoute", new { touristRouteId }),
                    "get_pictures",
                    "GET")
                );

            // 添加新图片
            links.Add(
                new LinkDto(
                    Url.Link("CreateTouristRoutePicture", new { touristRouteId }),
                    "create_picture",
                    "POST")
                );

            return links;
        }
        [HttpPost(Name = "CreateTouristRoute")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        [Authorize(Roles ="Admin")]//只有登录用户才能访问 上锁
        public async Task<IActionResult> CreateTouristRoute([FromBody] TouristRouteForCreationDto touristRouteForCreationDto)
        {
            var touristRouteModel = _mapper.Map<TouristRoute>(touristRouteForCreationDto);
            _touristRouteRepository.AddTouristRoute(touristRouteModel);
            await _touristRouteRepository.SaveAsync();
            var touristRouteToReture = _mapper.Map<TouristRouteDto>(touristRouteModel);
            //links
            var links = CreateLinkForTouristRoute(touristRouteModel.Id, null);

            var result = touristRouteToReture.ShapeData(null)
                as IDictionary<string, object>;

            result.Add("links", links);

            return CreatedAtRoute(
                "GetTouristRouteById",
                new { touristRouteId = touristRouteToReture.Id },
                touristRouteToReture
            );
        }

        [HttpPut("{touristRouteId}",Name = "UpdateTouristRoute")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> UpdateTouristRoute([FromRoute]Guid touristRouteId, [FromBody] TouristRouteForUpdateDto touristRouteForUpdateDto)
        {
            if(!(await _touristRouteRepository.TouristRouteExistsAsync(touristRouteId)))
            {
                return NotFound("旅游路线找不到！");
            }
            var touristRouteFromRepo=await _touristRouteRepository.GetToruistRouteAsync(touristRouteId);
            //1.映射DTo
            //2.更新DTO
            //3.映射MODEL
            _mapper.Map(touristRouteForUpdateDto, touristRouteFromRepo);
            await _touristRouteRepository.SaveAsync();
            //返回204壮态码 空
            return NoContent();
        }
        //局部更新path
        [HttpPatch("{touristRouteId}",Name = "PartiallyUpdateTouristRoute")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> PartiallyUpdateTouristRoute(
            [FromRoute] Guid touristRouteId, 
            [FromBody] JsonPatchDocument<TouristRouteForUpdateDto> patchDocument
            )
        {
            if(!(await _touristRouteRepository.TouristRouteExistsAsync(touristRouteId)))
            {

                return NotFound("旅游路线找不到");
                
            }
            var touristRouteFromRepo = await _touristRouteRepository.GetToruistRouteAsync(touristRouteId);
            var touristRouteToPatch = _mapper.Map<TouristRouteForUpdateDto>(touristRouteFromRepo);
            //原始数据打上补丁
            patchDocument.ApplyTo(touristRouteToPatch,ModelState);
            //json文档 title-description 数据校验
            if (!TryValidateModel(touristRouteToPatch))
            {
                return ValidationProblem(ModelState);
            }
            //数据保存到数据库
            _mapper.Map(touristRouteToPatch, touristRouteFromRepo);
            await _touristRouteRepository.SaveAsync();
            return NoContent();

        }
        //删除某条数据
        [HttpDelete("{touristRouteId}",Name = "DeleteTouristRoute")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> DeleteTouristRoute([FromRoute] Guid touristRouteId)
        {
            if(!(await _touristRouteRepository.TouristRouteExistsAsync(touristRouteId)))
            {
                return NotFound("旅游路线找不到！");
            }
            var touristRoute=await _touristRouteRepository.GetToruistRouteAsync(touristRouteId);
            _touristRouteRepository.DeleteTouristRoute(touristRoute);
            await _touristRouteRepository.SaveAsync();

            return NoContent();
        }
        //批量删除一组数据
        [HttpDelete("({touristIDs})")]
        [Authorize(Roles = "Admin")]
        public async Task<IActionResult> deleteByIDs([ModelBinder(BinderType=typeof(ArrayModelBinder))][FromRoute]IEnumerable<Guid> touristIDs)
        {
            if(touristIDs==null)
            {
                return BadRequest();
            }
            var touristRoutesFromRepo=await _touristRouteRepository.GetTouristRoutesByIDListAsync(touristIDs);
            _touristRouteRepository.DeleteTouristRoutes(touristRoutesFromRepo);
            await _touristRouteRepository.SaveAsync();
            return NoContent();
        }
       

    }
}
